﻿using System;
using Microsoft.Xna.Framework;
using RhythmComet;

namespace FMOD
{
#if !XBOX
    public sealed class fmodBeatDetector : IBeatDetector
    {
        RhythmCometGame game;
        float[] averageEnergy;
        float totalEnergy;
        float lastEnergyValue;
        float currentEnergy;
        int beginFrequency;
        int endFrequency;
        float deviation;
        int begin;
        private bool beat;
        const float noiseOffset = 0.0002f;
        public bool Enabled = true;
        const float frameTime = 0.024f;
        DateTime lastUpdateTime;
        private float timeSinceLastSpawn;
        private float spawnTime;

        public float Energy
        {
            get { return currentEnergy; }
        }

        public bool Beat
        {
            get { 
                if (!Enabled)
                    return false;
                return beat;
            }
        }

        public fmodBeatDetector(Game game, int begin, int end, float deviation, float spawnTime, float timeBufferLength)
        {
            this.game = (RhythmCometGame)game;
            float initialValue = 1.0f;
            int frameNumbers = (int)Math.Ceiling((double)(timeBufferLength / frameTime));

            this.beginFrequency = begin;
            this.endFrequency = end;
            this.deviation = deviation;
            this.begin = 0;
            this.spawnTime = spawnTime;

            this.averageEnergy = new float[42];
            this.totalEnergy = 0.0f;
            for (int i = 0; i < averageEnergy.Length; i++)
            {
                this.averageEnergy[i] = initialValue;
                this.totalEnergy += this.averageEnergy[i];
            }
            lastUpdateTime = DateTime.Now;
            this.currentEnergy = 0.0f;
            timeSinceLastSpawn = 0.0f;
            Enabled = true;
        }

        public void ReadFrequencies(float[] frequency)
        {
            float energy = 0.0f;
            for (int i = beginFrequency; i < endFrequency; i++)
            {
                if (frequency[i] > noiseOffset)
                    energy += frequency[i];
            }

            float E = 0.0f;
            E = totalEnergy / 43;

            lastEnergyValue = averageEnergy[begin];
            averageEnergy[begin] = energy;
            begin = (begin + 1) % averageEnergy.Length;

            totalEnergy = totalEnergy - lastEnergyValue + energy;

            if (energy > E * deviation)
            {
                this.currentEnergy = energy;
                this.beat = true;
            }
            else
            {
                this.currentEnergy = 0.0f;
                this.beat = false;
            }
        }

        public void Update(GameTime gameTime)
        {
            if ((DateTime.Now - lastUpdateTime).TotalSeconds > frameTime)
            {
                game.Player.SetSpectrum();
                ReadFrequencies(game.Player.Spectrum);
                lastUpdateTime = DateTime.Now;
            }
        }

        public bool OkToSpawn(GameTime gameTime)
        {
            timeSinceLastSpawn += (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (timeSinceLastSpawn > spawnTime)
            {
                timeSinceLastSpawn = 0.0f;
                return true;
            }
            return false;
        }

        public void Reset()
        {
            float initialValue = 1.0f;
            this.totalEnergy = 0.0f;
            for (int i = 0; i < averageEnergy.Length; i++)
            {
                this.averageEnergy[i] = initialValue;
                this.totalEnergy += this.averageEnergy[i];
            }
            lastUpdateTime = DateTime.Now;
            currentEnergy = 0.0f;
            timeSinceLastSpawn = 0.0f;
        }

        public void Toggle()
        {
            Enabled = !Enabled;
        }
    }
#endif
}
